using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace ITC_KEYBOARD
{
    /// <summary>
    /// a class to manage shiftKey entries
    /// </summary>
    public class CShiftKeys
    {
        public CUSBkeys.usbKeyStructShort ShiftKeyStruct;
        ///// <summary>
        ///// a ShiftKeys is similar to an USBKeyStruct except to that
        ///// it does not have an USB code page and USB HID scancode
        ///// </summary>
        //[Serializable]
        //[StructLayout(LayoutKind.Sequential)]
        //public struct ModifierKeyStruct
        //{
        //    /// <summary>
        //    /// high byte flags for the key definition
        //    /// </summary>
        //    public byte bFlagHigh;
        //    /// <summary>
        //    /// mid byte flags for the key definition
        //    /// </summary>
        //    public byte bFlagMid;
        //    /// <summary>
        //    /// low byte flags for the key definition
        //    /// </summary>
        //    public byte bFlagLow;
        //    /// <summary>
        //    /// the value generated by the key entry, a VKEY or an index into another table
        //    /// </summary>
        //    public byte bIntScan;
        //}
        /// <summary>
        /// gives a text dump reprensentation of the multikey
        /// </summary>
        /// <param name="_theBytes">the ModifierKeyStruct to dump</param>
        /// <returns>a string with the meanings of the structure</returns>
        public string dumpShiftKey(CUSBkeys.usbKeyStructShort _theBytes)
        {
            byte b;
            b = (byte)_theBytes.bFlagLow;
            string s = b.ToString("X02");
            b = (byte)_theBytes.bFlagMid;
            s += "," + b.ToString("X02");
            b = (byte)_theBytes.bFlagHigh;
            s += "," + b.ToString("X02");
            s += "," + _theBytes.bIntScan.ToString("X02");

            //getName does not care about extended etc...
            
            s += " '" + ITC_KEYBOARD.CUSBPS2_vals.Cusbps2key.getName(_theBytes.bIntScan) + "'";
            s += " | ";
            return s;
        }
        /// <summary>
        /// gives a text dump reprensentation of the multikey
        /// </summary>
        /// <param name="iIdx">the index of the ModifierKeyStruct to dump</param>
        /// <returns>a string with the meanings of the structure</returns>
        public string dumpShiftKey(int iIdx)
        {
            byte[] bs = _ShiftKeyStructList[iIdx - 1];
            CUSBkeys.usbKeyStructShort rs = RawDeserialize2(bs);
            string s = "->";
            s += dumpShiftKey(rs);
            return s;
        }

        private CUSBkeys.usbKeyStructShort[] _ShiftKeyStructs;

        private int _shiftKeyCount = 0;
        private List<byte[]> _ShiftKeyStructList;

        public CShiftKeys()
        {
            //read number of entries
            int iCount = this.getShiftKeyCount();
            if (iCount == 0)
                throw new ArgumentNullException("Sorry, no ShiftKeys supported");
            //create new arrays
            _ShiftKeyStructList=new List<byte[]>(iCount+1);
            this.readAll();
        }
        /// <summary>
        /// converts an array of ModifierKeyStruct to a byte array for
        /// storing into registry
        /// </summary>
        /// <param name="structData">the array to convert</param>
        /// <returns>a byte array ready to save to registry</returns>
        public byte[] RawSerialize(CUSBkeys.usbKeyStructShort[] structData)
        {
            //size
            int structSize = Marshal.SizeOf(structData[0]);
            int iRawSize = structData.Length * structSize;
            byte[] rawDatas = new byte[iRawSize];
            for (int i = 0; i < structData.Length; i++)
            {
                rawDatas[(i * structSize) + 0] = (byte)structData[i].bFlagHigh;
                rawDatas[(i * structSize) + 1] = (byte)structData[i].bFlagMid;
                rawDatas[(i * structSize) + 2] = (byte)structData[i].bFlagLow;
                rawDatas[(i * structSize) + 3] = (byte)structData[i].bIntScan;
            }
            return rawDatas;
        }
        /// <summary>
        /// converts a byte arrray as read from registry
        /// to an array of ModifierKeyStruct
        /// </summary>
        /// <param name="rawData">the bytes as read from registry</param>
        /// <returns>array of ModifierKeyStruct</returns>
        private static CUSBkeys.usbKeyStructShort RawDeserialize2(byte[] rawData)
        {
            int structSize = 4;
            int iCount = rawData.Length / structSize; //we have 4 bytes per struct
            CUSBkeys.usbKeyStructShort[] _multiStruct = new CUSBkeys.usbKeyStructShort[iCount];
            for (int i = 0; i < iCount; i++)
            {
                _multiStruct[i].bFlagHigh = (CUsbKeyTypes.usbFlagsHigh)rawData[i * structSize + 0];
                _multiStruct[i].bFlagMid = (CUsbKeyTypes.usbFlagsMid)rawData[i * structSize + 1];
                _multiStruct[i].bFlagLow = (CUsbKeyTypes.usbFlagsLow)rawData[i * structSize + 2];
                _multiStruct[i].bIntScan = rawData[i * structSize + 3];
            }
            return _multiStruct[0]; //return first struct only, there should be only one struct
        }

        public CUSBkeys.usbKeyStructShort getShiftKey(int idx)
        {
            int iMax = getShiftKeyCount();
            if (idx > iMax)
                return new CUSBkeys.usbKeyStructShort();
            return _ShiftKeyStructs[idx];

        }

        /// <summary>
        /// get the number of defined ModifierKeys as readable from registry
        /// </summary>
        /// <returns>the number of ModifierKeys</returns>
        public int getShiftKeyCount()
        {
            string regKeyb = CUSBkeys.getRegLocation() + @"\ShiftKeys";
            Microsoft.Win32.RegistryKey tempKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(regKeyb, true);
            int i = 1;
            object o = null;
            do
            {
                try
                {
                    o = tempKey.GetValue("ShiftKey" + i.ToString());
                }
                catch (Exception)
                {
                    o = null;
                    break;
                }
                if(o!=null)
                    i++;
            } while (o!=null);

            _shiftKeyCount = i-1;
            if (i != 0)
                return i - 1;
            else
                return 0;
        }

        private void readAll()
        {
            int iCount = this.getShiftKeyCount();
            if (iCount == 0)
                return;
            //read all ModifierKeys entries
            _ShiftKeyStructs = new CUSBkeys.usbKeyStructShort[iCount];

            string regKeyb = CUSBkeys.getRegLocation() + @"\ShiftKeys";
            Microsoft.Win32.RegistryKey tempKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(regKeyb, true);


            for (int i = 0; i < iCount; i++)
            {
                byte[] bModifierKeys = (byte[])tempKey.GetValue("ShiftKey" + (i+1).ToString());
                _ShiftKeyStructs[i] = RawDeserialize2(bModifierKeys);
                _ShiftKeyStructList.Add(bModifierKeys);
            }
            tempKey.Close();
            System.Diagnostics.Debug.WriteLine("ShiftKeys readall finished");
        }

    }
}
